/*
 * exame_2010_11_junho_Q4.c
 *
 *  Created on: Jun 18, 2012
 *      Author: ubuntu
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define AS 1
#define DUQUE 2
#define TERNO 3
#define QUADRA 4
#define QUINA 5
#define SENA 6
#define BISCA 7
#define OITO 8
#define NOVE 9
#define DEZ 10
#define REI 11
#define VALETE 12
#define DAMA 13

#define OUROS 0
#define PAUS 1
#define ESPADAS 2
#define COPAS 3

#define NUM_CARTAS_BARALHO 52
#define NUM_JOGADORES 4
#define NUM_CARTAS_MAO (NUM_CARTAS_BARALHO/NUM_JOGADORES)

typedef struct _carta {
	int naipe;
	int numero;
	int pontos;
	int indiceValor;
	int flagCartaDada;
	int flagCartaJogada;
} Carta;

typedef struct _baralho {
	Carta *cartas[NUM_CARTAS_BARALHO];
} Baralho;

typedef struct _vasa {
	Carta * jogada[NUM_JOGADORES];
} Vasa;

typedef struct _mao {
	Carta * cartas[NUM_CARTAS_MAO];
} Mao;

typedef struct _jogador {
	int numeroJogador;
	char * nome;
	Mao * mao;
	Vasa * vasas[NUM_CARTAS_MAO]; // No pior caso fica com as vasas todas
	int numeroCartasEmJogo;
	int numeroVasasGanhas;
} Jogador;

typedef struct _mesa {
	int jogadaActual;
	Vasa * jogadas[NUM_CARTAS_MAO];
	Jogador jogadores[NUM_JOGADORES];
} Mesa;

char * obterNomeCarta(int numero) {

	char * descricaoNumero = NULL;
	switch (numero) {
	case AS:
		descricaoNumero = "As";
		break;
	case DUQUE:
		descricaoNumero = "duque";

		break;
	case TERNO:
		descricaoNumero = "Terno";
		break;
	case QUADRA:
		descricaoNumero = "Quadra";
		break;
	case QUINA:
		descricaoNumero = "Quina";
		break;
	case SENA:
		descricaoNumero = "Sena";
		break;
	case BISCA:
		descricaoNumero = "Bisca";
		break;
	case OITO:
		descricaoNumero = "Oito";
		break;
	case NOVE:
		descricaoNumero = "Nove";
		break;
	case DEZ:
		descricaoNumero = "Dez";
		break;
	case REI:
		descricaoNumero = "Rei";
		break;
	case VALETE:
		descricaoNumero = "Valete";
		break;
	case DAMA:
		descricaoNumero = "Dama";
		break;
	default:
		break;
	}

	return descricaoNumero; //+ " " + descricaoNaipe;
}

char * obterNomeNaipe(int naipe) {
	char * descricaoNaipe = NULL;
	switch (naipe) {
	case OUROS:
		descricaoNaipe = "Ouros";
		break;
	case COPAS:
		descricaoNaipe = "Copas";
		break;
	case PAUS:
		descricaoNaipe = "Paus";
		break;
	case ESPADAS:
		descricaoNaipe = "Espadas";
		break;
	default:
		break;
	}
	return descricaoNaipe;
}

Baralho * obterBaralho() {
	Baralho * baralho = (Baralho *) malloc(sizeof(Baralho));
	int i = 0;
	for (i = 0; i < NUM_CARTAS_BARALHO; i++) {
		Carta * carta = (Carta *) malloc(sizeof(Carta));
		carta->flagCartaDada = 0;
		carta->flagCartaJogada = 0;
		carta->naipe = i % NUM_JOGADORES;
		carta->numero = i % NUM_CARTAS_MAO + 1;
		int pontos = 0;
		int indiceValor = 0;
		switch (carta->numero) {
		case AS:
			pontos = 11;
			indiceValor = 13;
			break;
		case DUQUE:
			pontos = 0;
			indiceValor = 1;
			break;
		case TERNO:
			pontos = 0;
			indiceValor = 2;
			break;
		case QUADRA:
			pontos = 0;
			indiceValor = 3;
			break;
		case QUINA:
			pontos = 0;
			indiceValor = 4;
			break;
		case SENA:
			pontos = 0;
			indiceValor = 5;
			break;
		case BISCA:
			pontos = 10;
			indiceValor = 12;
			break;
		case OITO:
			pontos = 0;
			indiceValor = 6;
			break;
		case NOVE:
			pontos = 0;
			indiceValor = 7;
			break;
		case DEZ:
			pontos = 0;
			indiceValor = 8;
			break;
		case REI:
			pontos = 4;
			indiceValor = 11;
			break;
		case VALETE:
			pontos = 3;
			indiceValor = 10;
			break;
		case DAMA:
			pontos = 2;
			indiceValor = 9;
			break;
		default:
			break;
		}
		carta->indiceValor = indiceValor;
		carta->pontos = pontos;
		baralho->cartas[i] = carta;
	}
	return baralho;
}

Mao * obterMao(Baralho * baralho, int numeroCartas) {
	Mao * mao = (Mao *) malloc(sizeof(Mao));
	int i = 0;
	int conta = 0;
	for (i = 0; i < NUM_CARTAS_BARALHO; i++) {
		if (baralho->cartas[i]->flagCartaDada == 1) {
			continue; // carta já consta deu uma outra mão
		}
		mao->cartas[conta] = baralho->cartas[i];
		baralho->cartas[i]->flagCartaDada = 1;
		conta++;
		if (conta == numeroCartas) // Mao completa
				{
			break;
		}

	}
	if (conta != numeroCartas) // Se Mao n esta completa
			{
		fprintf(stderr, "Erro interno conta == numeroCartas failed %d| %d\n",
				conta, numeroCartas);
		exit(EXIT_FAILURE);
	}
	return mao;
}

Mesa* obterMesa() {
	Mesa * mesa = (Mesa *) malloc(sizeof(Mesa));
	mesa->jogadaActual = 0;
	int i = 0;
	for (i = 0; i < NUM_CARTAS_MAO; i++) {
		mesa->jogadas[i] = (Vasa*) malloc(sizeof(Vasa));
	}
	return mesa;
}

void lerInfoJogadores(Baralho * baralho, Mesa * mesa) {
	int i = 0;
	for (i = 0; i < NUM_JOGADORES; i++) {
		char nome[100];
		printf("Nome %d jogador\n", i + 1);
		scanf("%s", nome);
		mesa->jogadores[i].nome = strdup(nome);
		mesa->jogadores[i].numeroJogador = i;
		mesa->jogadores[i].numeroCartasEmJogo = NUM_CARTAS_MAO;
		mesa->jogadores[i].mao = obterMao(baralho, NUM_CARTAS_MAO);
		mesa->jogadores[i].numeroVasasGanhas = 0;
	}

}

int jogarJogada(Mesa * mesa, int jogadorQueComeca) {
	int naipeEscolhido = -1;

	int j = 0;
	int conta = 0;
	for (conta = 0, j = jogadorQueComeca; conta < NUM_JOGADORES; conta++, j++) {
		if (j == NUM_JOGADORES) { // se deu a volta
			j = 0;
		}
		puts(": : : : : : : :");

		if (conta > 0) {
			puts("Cartas na mesa");
			int k = 0;
			int conta2 = 0;
			for (conta2 = 0, k = jogadorQueComeca; conta2 < conta;
					conta2++, k++) {
				if (k == NUM_JOGADORES) { // se deu a volta
					k = 0;
				}
				printf("[%s] %s de %s \n", mesa->jogadores[k].nome,
						obterNomeCarta(
								mesa->jogadas[mesa->jogadaActual]->jogada[k]->numero),
						obterNomeNaipe(
								mesa->jogadas[mesa->jogadaActual]->jogada[k]->naipe));
			}
		}
		printf("Jogador %s\n", mesa->jogadores[j].nome);
		puts(". . . . . . . .");
		int k = 0;
		puts("Cartas disponiveis");
		int contaCartasDisponiveis = 0;
		for (k = 0; k < NUM_CARTAS_MAO; k++) {

			if (naipeEscolhido == -1) {
				if (mesa->jogadores[j].mao->cartas[k]->flagCartaJogada == 0) {
					printf("[%d] %s de %s \n", k + 1,
							obterNomeCarta(
									mesa->jogadores[j].mao->cartas[k]->numero),
							obterNomeNaipe(
									mesa->jogadores[j].mao->cartas[k]->naipe));

					contaCartasDisponiveis++;
				}
			} else {
				if (mesa->jogadores[j].mao->cartas[k]->flagCartaJogada == 0
						&& mesa->jogadores[j].mao->cartas[k]->naipe
								== naipeEscolhido) {
					printf("[%d] %s de %s \n", k + 1,
							obterNomeCarta(
									mesa->jogadores[j].mao->cartas[k]->numero),
							obterNomeNaipe(
									mesa->jogadores[j].mao->cartas[k]->naipe));
					contaCartasDisponiveis++;
				}
			}
		}
		if (contaCartasDisponiveis == 0) {
			// entao apresentar cartas disponiveis, sem restricao de naipe
			for (k = 0; k < NUM_CARTAS_MAO; k++) {

				if (mesa->jogadores[j].mao->cartas[k]->flagCartaJogada == 0) {
					printf("[%d] %s de %s \n", k + 1,
							obterNomeCarta(
									mesa->jogadores[j].mao->cartas[k]->numero),
							obterNomeNaipe(
									mesa->jogadores[j].mao->cartas[k]->naipe));
				}
			}
		}

		puts("Escolher carta");
		int cartaEscolhida = 0;
		scanf("%d", &cartaEscolhida);
		cartaEscolhida--; // para voltar aos indices a começar em 0

		mesa->jogadores[j].mao->cartas[cartaEscolhida]->flagCartaJogada = 1;

		mesa->jogadores[j].numeroCartasEmJogo++;

		mesa->jogadas[mesa->jogadaActual]->jogada[j] =
				mesa->jogadores[j].mao->cartas[cartaEscolhida];

		if (naipeEscolhido == -1) {
			puts("f");
			naipeEscolhido =
					mesa->jogadores[j].mao->cartas[cartaEscolhida]->naipe;
			printf("Escolhido naipe de %s\n", obterNomeNaipe(naipeEscolhido));
		}

	}
	int indiceJogadorPerdedor = -1;
	int maxIndice = -1;
	for (j = 0; j < NUM_JOGADORES; j++) {

		if (mesa->jogadas[mesa->jogadaActual]->jogada[j]->indiceValor
				> maxIndice) {
			maxIndice =
					mesa->jogadas[mesa->jogadaActual]->jogada[j]->indiceValor;
			indiceJogadorPerdedor = j;
		}
	}
	mesa->jogadores[indiceJogadorPerdedor].vasas[mesa->jogadores[indiceJogadorPerdedor].numeroVasasGanhas] =
			mesa->jogadas[mesa->jogadaActual];

	mesa->jogadores[indiceJogadorPerdedor].numeroVasasGanhas++;

	printf("Jogador %s, acumula agora %d vasas.\n",
			mesa->jogadores[indiceJogadorPerdedor].nome,
			mesa->jogadores[indiceJogadorPerdedor].numeroVasasGanhas);

	return indiceJogadorPerdedor;
}

int main(int argc, char **argv) {
	puts("Iniciar app");
	puts("Criar baralho");
	Baralho * baralho = obterBaralho();
	puts("Iniciar Mesa");
	Mesa * mesa = obterMesa();

	puts("Obter Nomes Jogadores");
	lerInfoJogadores(baralho, mesa);

	puts("Iniciar Jogo");

	int i = 0;
	int jogadorSeguinte = 0;
	for (i = 0; i < NUM_CARTAS_MAO; i++) {
		puts("=========================================");
		printf("Iniciar %d Jogada\n", i + 1);
		puts("-----------------------------------------");
		mesa->jogadaActual = i;
		jogadorSeguinte = jogarJogada(mesa, jogadorSeguinte);
	}

	int indiceJogadorGanhador = -1;
	int numVasasGanhas = 99;
	for (i = 0; i < NUM_JOGADORES; i++) {
		if (mesa->jogadores[i].numeroVasasGanhas < numVasasGanhas) {
			numVasasGanhas = mesa->jogadores[i].numeroVasasGanhas;
			indiceJogadorGanhador = i;
		}
	}

	printf("Parabens %s\nGanhou o jogo com apenas %d vasas acumuladas\n",
			mesa->jogadores[indiceJogadorGanhador].nome,
			mesa->jogadores[indiceJogadorGanhador].numeroVasasGanhas);

	return 0;
}

